/*-----------------------------------------------------------------------------
		   Licensed to the Apache Software Foundation (ASF) under one
           or more contributor license agreements.  See the NOTICE file
           distributed with this work for additional information
           regarding copyright ownership.  The ASF licenses this file
           to you under the Apache License, Version 2.0 (the
           "License"); you may not use this file except in compliance
           with the License.  You may obtain a copy of the License at

             http://www.apache.org/licenses/LICENSE-2.0

           Unless required by applicable law or agreed to in writing,
           software distributed under the License is distributed on an
           "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
           KIND, either express or implied.  See the License for the
           specific language governing permissions and limitations
           under the License.  
-----------------------------------------------------------------------------*/

package data;

import java.io.File;
import java.util.ArrayList;

/**
 * This class represents a source file which is composed of many fields, and
 * contains the methods found within the file. There are simple metrics that 
 * can be applied to these objects. 
 * <p>They are the base of the hierarchy structure {@link SFile} > 
 * {@link SFolder} > {@link SMethod}
 * <p> SLOC = Source Lines of Code <p> CC = Cyclomatic Complexity
 * 
 * @author Kevin.J.Jalbert
 */
public class SFile {

	private String fileName = null;
	private String filePath = null;
	private float fileSize = 0;
	private float charactersWithComments = 0;
	private float charactersWithoutComments = 0;
	private String cleanCode = "";
	private ArrayList<SMethod> allMethods = new ArrayList<SMethod>();

	/**
	 * Instantiates a new {@link SFile} with data about the file.
	 * 
	 * @param node the file node
	 * @param charactersWithComments the number of characters using with comments
	 * @param charactersWithoutComments the number of characters using without comments
	 * @param cleanCode the clean code of the file
	 */
	public SFile(File node, float charactersWithComments, float charactersWithoutComments, String cleanCode){
		this.fileName = node.getName();

		// Remove the actual file name from the path
		this.filePath = node.getAbsolutePath();
		this.filePath = this.filePath.substring(0, this.filePath.length()-this.fileName.length());

		this.fileSize = node.length();
		this.charactersWithComments = charactersWithComments;
		this.charactersWithoutComments = charactersWithoutComments;
		this.cleanCode = cleanCode;
	}

	/**
	 * Adds the a {@link SMethod} to this file.
	 * 
	 * @param method the method
	 */
	public void addSMethod(SMethod method){
		allMethods.add(method);
	}

	/**
	 * Gets the arraylist of {@link SMethod} in this file.
	 * 
	 * @return allMethods the arraylist of all {@link SMethods}
	 */
	public ArrayList<SMethod> getSMethod(){
		return allMethods;
	}

	/**
	 * Gets the clean code of this file.
	 * 
	 * @return the clean code
	 */
	public String getCleanCode() {
		return cleanCode;
	}

	/**
	 * Resets the clean code to conserve space; it is really used only once, can
	 * remove this method if needed.
	 */
	public void clearCleanCode() {
		cleanCode = "";
	}

	/**
	 * Gets the file name.
	 * 
	 * @return fileName the file name
	 */
	public String getFileName() {
		return fileName;
	}

	/**
	 * Gets the file path.
	 * 
	 * @return filePath the file path
	 */
	public String getFilePath() {
		return filePath;
	}

	/**
	 * Gets the file size.
	 * 
	 * @return fileSize the file size
	 */
	public float getFileSize() {
		return fileSize;
	}

	/**
	 * Gets the characters using with comments.
	 * 
	 * @return charactersWithComments the characters using with comments
	 */
	public float getCharactersWithComments() {
		return charactersWithComments;
	}

	/**
	 * Gets the characters using without comments.
	 * 
	 * @return charactersWithoutComments the characters using without comments
	 */
	public float getCharactersWithoutComments() {
		return charactersWithoutComments;
	}

	/**
	 * Gets the comment ratio of the file.
	 * 
	 * @return commentRatio the comment ratio of the file
	 */
	public float getCommentRatio() {

		float commentRatio = 0;

		if ( charactersWithoutComments == 0){
			commentRatio = -1;
		}
		else{
			commentRatio = (1-(charactersWithoutComments / charactersWithComments)) * 100;
		}

		return commentRatio;
	}	

	/**
	 * Gets the source lines of the file. <p>
	 * Based off of the method's source lines which does not encapsulate all other
	 * portions of the code (headers, includes, imports, defines, etc...)
	 * 
	 * @return sourceLines the source lines
	 */
	public float getSourceLines(){

		float sourceLines = 0;

		for (SMethod method : allMethods){
			sourceLines += method.getSourceLines();
		}

		return sourceLines;
	}

	/**
	 * Gets the cyclomatic complexity of the file.
	 * 
	 * @return cyclo the cyclomatic complexity
	 */
	public int getCyclo(){
		int cyclo = 0;

		for(SMethod method : allMethods){
			cyclo += method.getCyclo();
		}
		return cyclo;
	}

	/**
	 * Gets the SLOC per CC of the whole file.
	 * 
	 * @return totalSLOCPerCC the CLOC per CC of the whole file
	 */
	public float getSLOCPerCC() {

		float totalSLOCPerCC = 0;

		if (getCyclo() == 0){
			totalSLOCPerCC = -1;
		}
		else{
			totalSLOCPerCC = (getSourceLines() / getCyclo());
		}

		return totalSLOCPerCC;
	}

	/**
	 * Gets the average CC for this file, of all methods within it.
	 * 
	 * @return average CC the average CC of all methods in file
	 */
	public float getAverageCC() {

		float averageCC = 0;

		if (allMethods.size() == 0){
			averageCC = -1;
		}
		else{
			averageCC = (getCyclo()/allMethods.size());
		}

		return averageCC;
	}

	/**
	 * Gets the average SLOC per CC for all methods in this file.
	 * 
	 * @return averageSLOCPerCC the average SLOC per CC of all methods in file
	 */
	public float getAverageSLOCperCC() {

		float averageSLOCPerCC = 0;

		if (allMethods.size() == 0 || getCyclo() == 0){
			averageSLOCPerCC = -1;
		}
		else{
			averageSLOCPerCC = ((getSourceLines() / getCyclo())/allMethods.size());
		}

		return averageSLOCPerCC;
	}

	/**
	 * Gets the highest method CC in file.
	 * 
	 * @return highCC the highest CC method in file
	 */
	public int getHighCC() {
		int highCC = 0;

		for(SMethod method : allMethods){
			if (method.getCyclo() > highCC){
				highCC = method.getCyclo();
			}
		}		

		return highCC;
	}

	/**
	 * Gets the highest method SLOC in file.
	 * 
	 * @return highSLOC the highest SLOC method in file
	 */
	public int getHighSLOC() {
		int highSLOC = 0;

		for(SMethod method : allMethods){
			if (method.getSourceLines() > highSLOC){
				highSLOC = method.getSourceLines();
			}
		}		

		return highSLOC;
	}


	/**
	 * Gets the lowest method CC in file.
	 * 
	 * @return lowCC the lowest CC method in file
	 */
	public int getLowCC() {
		int lowCC = 65354;

		for(SMethod method : allMethods){
			if (method.getCyclo() < lowCC){
				lowCC = method.getCyclo();
			}
		}		

		return lowCC;
	}

	/**
	 * Gets the lowest method SLOC in file.
	 * 
	 * @return lowCC the lowest SLOC method in file
	 */
	public int getLowSLOC() {
		int lowSLOC = 65534;

		for(SMethod method : allMethods){
			if (method.getSourceLines() < lowSLOC){
				lowSLOC = method.getSourceLines();
			}
		}		

		return lowSLOC;
	}
}